#include "test.h"
#include "list.h"

bool test_create()
{
	list l;

	ASSERT_EQUALS(list_init(NULL), LIST_ERROR);
	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_get_size()
{
	list l;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_size(&l), 0);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 0), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 1);
	ASSERT_EQUALS(list_remove_head(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 0);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_get_head()
{
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(NULL, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(&l, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(NULL, &it), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);	
	ASSERT_EQUALS(list_is_end(&l, &it), 1);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 0), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 0);
	ASSERT_EQUALS(list_is_end(&l, &it), 0);
	ASSERT_EQUALS(list_remove_head(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(list_is_end(&l, &it), 1);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 1), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 2), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 3), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 3);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_get_tail()
{
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_tail(NULL, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_tail(&l, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_tail(NULL, &it), LIST_ERROR);
	ASSERT_EQUALS(list_get_tail(&l, &it), LIST_END);	
	ASSERT_EQUALS(list_is_end(&l, &it), 1);
	ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) 0), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_tail(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 0);
	ASSERT_EQUALS(list_is_end(&l, &it), 0);
	ASSERT_EQUALS(list_remove_tail(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_tail(&l, &it), LIST_END);
	ASSERT_EQUALS(list_is_end(&l, &it), 1);
	ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) 1), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) 2), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) 3), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_tail(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 3);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_is_end()
{
	list l;
	iterator it;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_is_end(NULL, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_is_end(&l, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_is_end(NULL, &it), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(list_is_end(&l, &it), 1);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 0), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(list_is_end(&l, &it), 0);
	ASSERT_EQUALS(list_remove_tail(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(list_is_end(&l, &it), 1);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_get_next()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_next(NULL, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_next(&l, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_next(NULL, &it), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(list_get_next(&l, &it), LIST_END);

	for (i = 0; i < 10; ++i) {
		ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) i), LIST_SUCCESS);
	}

	i = 0;
	for (list_get_head(&l, &it); !(list_is_end(&l, &it)); list_get_next(&l, &it)) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		++i;
	}

	i = 0;
	LIST_FOREACH(&l, &it) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		++i;
	}

	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_insert_before()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_before(NULL, NULL, (list_element_t) 0), LIST_ERROR);
	ASSERT_EQUALS(list_insert_before(&l, NULL, (list_element_t) 0), LIST_ERROR);
	ASSERT_EQUALS(list_insert_before(NULL, &it, (list_element_t) 0), LIST_ERROR);

	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(list_insert_before(&l, &it, (list_element_t) 5), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_before(&l, &it, (list_element_t) 4), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 4);
	ASSERT_EQUALS(list_get_next(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 5);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_before(&l, &it, (list_element_t) 3), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_before(&l, &it, (list_element_t) 2), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 1), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_before(&l, &it, (list_element_t) 0), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 6);

	i = 0;
	LIST_FOREACH(&l, &it) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		++i;
	}

	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_insert_after()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_after(NULL, NULL, (list_element_t) 0), LIST_ERROR);
	ASSERT_EQUALS(list_insert_after(&l, NULL, (list_element_t) 0), LIST_ERROR);
	ASSERT_EQUALS(list_insert_after(NULL, &it, (list_element_t) 0), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(list_insert_after(&l, &it, (list_element_t) 1), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_after(&l, &it, (list_element_t) 2), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 1);
	ASSERT_EQUALS(list_get_next(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 2);
	ASSERT_EQUALS(list_insert_after(&l, &it, (list_element_t) 3), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_after(&l, &it, (list_element_t) 4), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_head(&l, (list_element_t) 0), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_tail(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_after(&l, &it, (list_element_t) 5), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 6);

	i = 0;
	LIST_FOREACH(&l, &it) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		++i;
	}

	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_insert_head()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_head(NULL, (list_element_t) 0), LIST_ERROR);

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_insert_head(&l, (list_element_t) i), LIST_SUCCESS);
	}

	i = 4;
	LIST_FOREACH(&l, &it) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		--i;
	}

	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_insert_tail()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_insert_tail(NULL, (list_element_t) 0), LIST_ERROR);

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) i), LIST_SUCCESS);
	}

	i = 0;
	LIST_FOREACH(&l, &it) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		++i;
	}

	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_remove()
{
	int i;
	list l;
	iterator it;
	list_element_t e;
	
	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_remove(NULL, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_remove(&l, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_remove(NULL, &it), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(list_remove(&l, &it), LIST_END);

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) i), LIST_SUCCESS);
	}

	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);

	for (i = 0; i < 5; ++i) {
		if (i % 2 == 0) {
			ASSERT_EQUALS(list_remove(&l, &it), LIST_SUCCESS);
		}
		else {
			ASSERT_EQUALS(list_get_next(&l, &it), LIST_SUCCESS);
		}
	}

	ASSERT_EQUALS(list_get_size(&l), 2);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 1);
	ASSERT_EQUALS(list_get_next(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 3);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(list_remove(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 1);
	ASSERT_EQUALS(l.head, l.tail);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 3);
	ASSERT_EQUALS(list_remove(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 0);
	ASSERT_EQUALS(l.head, l.tail);
	ASSERT_EQUALS(l.head, NULL);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_remove_head()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_remove_head(NULL), LIST_ERROR);
	ASSERT_EQUALS(list_remove_head(&l), LIST_END);

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) i), LIST_SUCCESS);
	}

	for (i = 0; i < 2; ++i) {
		ASSERT_EQUALS(list_remove_head(&l), LIST_SUCCESS);
	}

	ASSERT_EQUALS(list_get_size(&l), 3);

	i = 2;
	LIST_FOREACH(&l, &it) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		++i;
	}

	for (i = 0; i < 2; ++i) {
		ASSERT_EQUALS(list_remove_head(&l), LIST_SUCCESS);
	}

	ASSERT_EQUALS(list_get_size(&l), 1);
	ASSERT_EQUALS(l.head, l.tail);
	ASSERT_EQUALS(list_remove_head(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 0);
	ASSERT_EQUALS(l.head, l.tail);
	ASSERT_EQUALS(l.head, NULL);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_remove_tail()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_remove_tail(NULL), LIST_ERROR);
	ASSERT_EQUALS(list_remove_tail(&l), LIST_END);

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) i), LIST_SUCCESS);
	}

	for (i = 0; i < 2; ++i) {
		ASSERT_EQUALS(list_remove_tail(&l), LIST_SUCCESS);
	}

	ASSERT_EQUALS(list_get_size(&l), 3);

	i = 0;
	LIST_FOREACH(&l, &it) {
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
		++i;
	}

	for (i = 0; i < 2; ++i) {
		ASSERT_EQUALS(list_remove_head(&l), LIST_SUCCESS);
	}

	ASSERT_EQUALS(list_get_size(&l), 1);
	ASSERT_EQUALS(l.head, l.tail);
	ASSERT_EQUALS(list_remove_tail(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_size(&l), 0);
	ASSERT_EQUALS(l.head, l.tail);
	ASSERT_EQUALS(l.head, NULL);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_find()
{
	int i;
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(list_find(NULL, (list_element_t) 0, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_find(&l, (list_element_t) 0, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_find(NULL, (list_element_t) 0, &it), LIST_ERROR);
	ASSERT_EQUALS(list_find(&l, (list_element_t) 0, &it), LIST_END);

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) i), LIST_SUCCESS);
	}

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_find(&l, (list_element_t) i, &it), LIST_SUCCESS);
		ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
		ASSERT_EQUALS(e, (list_element_t) i);
	}

	ASSERT_EQUALS(list_find(&l, (list_element_t) 5, &it), LIST_END);
	ASSERT_EQUALS(list_is_end(&l, &it), 1);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);
	
	return true;
}

bool test_destroy()
{
	int i;
	list l;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);

	for (i = 0; i < 5; ++i) {
		ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) i), LIST_SUCCESS);
	}

	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

bool test_get_value()
{
	list l;
	iterator it;
	list_element_t e;

	ASSERT_EQUALS(list_init(&l), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(NULL, &e), LIST_ERROR);
	ASSERT_EQUALS(iterator_get_value(&it, NULL), LIST_ERROR);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_END);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_END);
	ASSERT_EQUALS(list_insert_tail(&l, (list_element_t) 0), LIST_SUCCESS);
	ASSERT_EQUALS(list_get_head(&l, &it), LIST_SUCCESS);
	ASSERT_EQUALS(iterator_get_value(&it, &e), LIST_SUCCESS);
	ASSERT_EQUALS(e, (list_element_t) 0);
	ASSERT_EQUALS(list_destroy(&l), LIST_SUCCESS);

	return true;
}

int main()
{
	RUN_TEST(test_create);
	RUN_TEST(test_get_size);
	RUN_TEST(test_get_head);
	RUN_TEST(test_get_tail);
	RUN_TEST(test_is_end);
	RUN_TEST(test_get_next);
	RUN_TEST(test_insert_before);
	RUN_TEST(test_insert_after);
	RUN_TEST(test_insert_head);
	RUN_TEST(test_insert_tail);
	RUN_TEST(test_remove);
	RUN_TEST(test_remove_head);
	RUN_TEST(test_remove_tail);
	RUN_TEST(test_find);
	RUN_TEST(test_destroy);
	RUN_TEST(test_get_value);

#ifdef _WIN32
	if (_CrtDumpMemoryLeaks()) {
		printf("Memory leaks!!!!\n");
	}
#endif

	return 0;
}